package com.gitee.ec.kernel;

import com.gitee.ec.EverythingClient;
import com.gitee.ec.common.*;
import com.sun.jna.WString;
import lombok.Getter;

import java.nio.CharBuffer;
import java.nio.IntBuffer;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author hongda.li
 */
@Getter
public class EverythingClientV4 implements EverythingClient {

    @Override
    public String version() {
        return EverythingLibraryAccessor.access(ins -> {
            int majorVersion = ins.Everything_GetMajorVersion();
            int minorVersion = ins.Everything_GetMinorVersion();
            int revision = ins.Everything_GetRevision();

            OperationStatus.checkError();

            return String.format(EverythingConstants.Library.VERSION_FORMAT, majorVersion, minorVersion, revision);
        });
    }

    @Override
    public int count(SearchCondition condition) {
        return EverythingLibraryAccessor.access(ins -> {
            // 应用检索条件
            this.applySearchCondition(condition, ins);

            // 检索并等待
            ins.Everything_QueryW(true);

            // 检索总数量
            int totalCount = ins.Everything_GetTotResults();

            // 重置查询条件
            ins.Everything_Reset();

            return totalCount;
        });
    }

    @Override
    public List<FileInfo> search(SearchCondition condition) {
        return EverythingLibraryAccessor.access(ins -> {
            // 应用检索条件
            this.applySearchCondition(condition, ins);

            // 检索并等待
            ins.Everything_QueryW(true);

            // 封装检索结果
            List<FileInfo> fileInfoList = Stream.iterate(0, i -> i + 1)
                    .limit(ins.Everything_GetNumResults())
                    .map(i -> this.buildFileInfo(condition.getOutputList(), ins, i))
                    .collect(Collectors.toList());

            // 重置查询条件
            ins.Everything_Reset();

            return fileInfoList;
        });
    }

    protected void applySearchCondition(SearchCondition condition, EverythingLibrary ins) {
        // 总数量
        ins.Everything_SetMax(condition.getLimit());
        // 偏移量
        ins.Everything_SetOffset(condition.getOffset());
        // 排序方式
        ins.Everything_SetSort(condition.getSortBy().getValue());
        // 启用正则
        ins.Everything_SetRegex(condition.getEnableMatchRegex());
        // 启用大小写匹配
        ins.Everything_SetMatchCase(condition.getEnableMatchCase());
        // 启用路径匹配
        ins.Everything_SetMatchPath(condition.getEnableMatchPath());
        // 检索表达式
        ins.Everything_SetSearchW(new WString(condition.getExpression()));
        // 启用全量检索词匹配
        ins.Everything_SetMatchWholeWord(condition.getEnableMatchWholeWord());
        // 指定检索项集合
        ins.Everything_SetRequestFlags(OutputItemName.calculate(condition.getOutputList()));
    }

    protected FileInfo buildFileInfo(List<OutputItemName> range, EverythingLibrary ins, int index) {
        // 文件标识
        boolean isFile = ins.Everything_IsFileResult(index);

        // 文件夹标识
        boolean isDirectory = ins.Everything_IsFolderResult(index);

        // 文件名称
        WString fileName = EverythingUtils.filterOutput(range,
                OutputItemName.EVERYTHING_REQUEST_FILE_NAME,
                () -> ins.Everything_GetResultFileNameW(index));

        // 文件所在目录路径
        WString directoryPath = EverythingUtils.filterOutput(range,
                OutputItemName.EVERYTHING_REQUEST_PATH,
                () -> ins.Everything_GetResultPathW(index));

        // 文件全路径
        CharBuffer fileAbsolutePath = CharBuffer.allocate(EverythingConstants.Searcher.BUFFER_SIZE);
        EverythingUtils.filterOutput(range,
                OutputItemName.EVERYTHING_REQUEST_FULL_PATH_AND_FILE_NAME,
                () -> ins.Everything_GetResultFullPathNameW(index, fileAbsolutePath, EverythingConstants.Searcher.BUFFER_SIZE));

        // 文件后缀
        WString extendName = EverythingUtils.filterOutput(range,
                OutputItemName.EVERYTHING_REQUEST_EXTENSION,
                () -> ins.Everything_GetResultExtensionW(index));

        // 文件大小
        IntBuffer fileSize = IntBuffer.allocate(1);
        EverythingUtils.filterOutput(range,
                OutputItemName.EVERYTHING_REQUEST_SIZE,
                () -> ins.Everything_GetResultSize(index, fileSize));

        // 文件修改时间
        FileTime modifyTime = new FileTime();
        EverythingUtils.filterOutput(range,
                OutputItemName.EVERYTHING_REQUEST_DATE_MODIFIED,
                () -> ins.Everything_GetResultDateModified(index, modifyTime));

        return new FileInfo()
                .setFileFlag(isFile)
                .setDirectoryFlag(isDirectory)
                .setFileSize(EverythingUtils.readDouble(fileSize))
                .setFileName(EverythingUtils.readString(fileName))
                .setModifyDate(EverythingUtils.readDate(modifyTime))
                .setExtendName(EverythingUtils.readString(extendName))
                .setDirectoryPath(EverythingUtils.readString(directoryPath))
                .setFileAbsolutePath(EverythingUtils.readString(fileAbsolutePath));
    }
}
